package com.majsubtense.main.gameScenes;

import com.majsubtense.core.components.*;
import com.majsubtense.core.components.Timer;
import com.majsubtense.core.GameScene;
import com.majsubtense.core.events.*;
import com.majsubtense.main.gameEntities.Racer;
import com.majsubtense.main.ui.RaceVenueUI;

import java.time.Duration;
import java.time.LocalDateTime;
import java.util.*;

public class RaceVenue extends GameScene {
    private final float raceLength = 400.0f;
    private final int racerNum = 3;
    private final List<Racer> racers = new ArrayList<>();
    private final List<Map.Entry<Racer, Duration>> winners = new ArrayList<>();
    private boolean isRacing = false;
    private LocalDateTime raceBeginTime;

    public RaceVenue() {
        addComponent(this, new Render());

        Sprite background = new Sprite();
        background.loadFromModule("/images/raceVenue.png");
        addComponent(this, background);

        RaceVenueUI raceVenueUI = new RaceVenueUI();
        addComponent(this, raceVenueUI);
        raceVenueUI.attach();

        UI.addListener(new EventHandler<>(
                GameSceneControlEvent.GAME_SCENE_RESET,
                gameControlEvent -> {
                    if (active) {
                        resetRace();
                        getComponent(RaceVenueUI.ANY).startScene();
                    }
                }
        ));
        UI.addListener(new EventHandler<>(
                GameSceneControlEvent.GAME_SCENE_START,
                gameControlEvent -> {
                    if (active)
                        startRace();
                })
        );

        Timer timer = new Timer() {
            @Override
            public void update(long deltaTime) {
                Render render = getComponent(Render.ANY);
                // Draw background.
                render.paint(getComponent(Sprite.ANY).getImage(), 0.0f, 0.0f);

                double distance;
                double seconds = deltaTime * 1.0f / 10e9;
                Transform racerTransform;
                float[] racerPosition, toPosition;
                for (Racer racer : racers) {
                    distance = (float) (racer.getSpeed() * seconds);
                    racerTransform = racer.getComponent(Transform.ANY);
                    racerPosition = racerTransform.getPosition();

                    if (racerPosition[0] >= raceLength) {
                        if (!racer.isWin()) {
                            LocalDateTime winTime = LocalDateTime.now();
                            Duration duration = Duration.between(raceBeginTime, winTime);
                            String str = String.format("%d.%d", duration.getSeconds(), (int) (duration.getNano() / 10e6));
                            getComponent(UI.ANY).showEffect(
                                    str,
                                    racerPosition
                            );
                            winners.add(new AbstractMap.SimpleEntry<>(racer, duration));
                        }
                        racer.setWin(true);
                    }

                    toPosition = new float[]{
                            (float) (racerPosition[0] + distance),
                            racerPosition[1]
                    };

                    if (isRacing && racerPosition[0] < raceLength)
                        racerTransform.setPosition(toPosition);

                    render.paint(
                            racer.getComponent(Sprite.ANY).getImage(),
                            racerPosition
                    );
                }
            }
        };
        addComponent(this, timer);

        Random random = new Random();
        for (int i = 0; i < racerNum; i++) {
            Racer racer = new Racer("Horse" + (i + 1), 0);
            racer.getComponent(Transform.ANY).setPositionY(150 + 80 * i);
            Sprite horse = new Sprite();
            horse.loadFromModule("/images/horse" + (i + 1) + "(1).jpg");
            racer.addComponent(this, horse);
            racers.add(racer);
        }
    }

    public void startRace() {
        raceBeginTime = LocalDateTime.now();
        resetRace();
        isRacing = true;
    }

    public void endRace() {
    }

    public void resetRace() {
        isRacing = false;
        Random random = new Random();
        for (Racer racer : racers) {
            racer.getComponent(Transform.ANY).setPositionX(0.0f);
            racer.setWin(false);
            racer.setSpeed(random.nextInt(400) + 600);
        }
    }

    @Override
    public void sceneStart() {
        getComponent(Timer.ANY).timerStart();
        getComponent(RaceVenueUI.ANY).startScene();
    }

    @Override
    public void sceneStop() {
        getComponent(Timer.ANY).timerStop();
        resetRace();
    }

    public float getRaceLength() {
        return raceLength;
    }

    public List<Racer> getRacers() {
        return racers;
    }
}
